package tests.experiments.resourcerelation;

import jeconbond.automata.INode;
import jeconbond.automata.Node;
import jeconbond.economic.EconomicEngine;
import jeconbond.economic.IEconomicEngine;
import jeconbond.economic.market.agent.service.ResellResourceExpensiveSpeculantAgent;
import jeconbond.economic.agent.IEconomicAgent;
import jeconbond.economic.agent.IEconomicProducer;
import jeconbond.economic.agent.service.NextStepCommandAgent;
import jeconbond.economic.resources.IResourceType;
import jeconbond.economic.resources.ResourceStorrage;
import jeconbond.economic.resources.ResourceType;
import jeconbond.economic.resources.ResourceUtils;
import jeconbond.economic.systems.market.DefaultMarketRRSFactory;
import jeconbond.economic.systems.market.DefaultMarketResourceRedestributionSystem;
import jeconbond.economic.systems.market.IMarketResourceRedestributionSystem;
import jeconbond.economic.systems.market.IMoneyAccount;
import jeconbond.economic.systems.market.ISellProposition;
import jeconbond.economic.systems.market.MoneyAccount;
import jeconbond.economic.systems.market.SellProposition;
import jeconbond.experiment.JEBExperimentFlow;
import jeconbond.experiment.market.resourcerelations.GraigExperimentSettings;
import jeconbond.experiment.market.resourcerelations.generate.AntBasedAgentsCreator;
import jeconbond.experiment.market.resourcerelations.generate.BrosnenEngineInitialiser;
import jeconbond.experiment.market.resourcerelations.generate.GoalGroupComplementaryBasedProfitCostGen;
import junit.framework.Assert;
import junit.framework.TestCase;
import laboratoryQ.experiment.process.IExperimentContext;
import laboratoryQ.flatness.Point;

public class TestBrosnenServices extends TestCase {
	public void testSpeculant() {
		final IResourceType wood = new ResourceType("Wood");
		final IMarketResourceRedestributionSystem mrrs = new DefaultMarketResourceRedestributionSystem();
		ResellResourceExpensiveSpeculantAgent speculant = 
			new ResellResourceExpensiveSpeculantAgent(
					wood,
					mrrs,
					0.1,
					1.0
			);
		IEconomicEngine engine = new EconomicEngine();
		final NextStepCommandAgent nsc = new NextStepCommandAgent(1); 
		engine.addAgents(nsc, speculant);
		engine.addAgents(
				new IEconomicAgent() {
					private IMoneyAccount money = new MoneyAccount(1e5);
					private ResourceStorrage storr = new ResourceStorrage();

					@Override
					public void processPreProduceStage() {
						if (nsc.stepCounter[0] == 3) {
							ISellProposition[] props = mrrs.getSellPropositionsList(wood);
							ISellProposition p = props[0];
							if (p.getSellerMoneyAccount() == money) {
								p = props[1];
							}
							ResourceUtils.processDeal(
									p, 
									20.0, 
									money, 
									storr, 
									mrrs
							);
						}
						storr.clear();
					}
					
					@Override
					public void processProduceStage() {
					}
					
					@Override
					public void processPostProduceStage() {
						storr.storeResource(
								wood,
								10.0 - storr.howMuchWasStored(wood)
						);
						mrrs.registerProposition(
								new SellProposition(
										wood,
										1.0 * (nsc.stepCounter[0] + 1),
										storr,
										money
								)
						);
					}
				}
		);
		
		engine.processSteps(1, mrrs);
		Assert.assertEquals(1, mrrs.getSellPropositionsList(wood).length);
		Assert.assertEquals(1.0, mrrs.getSellPropositionsList(wood)[0].getPrice());
		
		engine.processSteps(1, mrrs);
		ISellProposition[] props = mrrs.getSellPropositionsList(wood);
		ISellProposition p = props[0];
		if (p.getSellerMoneyAccount().getBalance() < 1e7) {
			p = props[1];
		}
		Assert.assertEquals(2, props.length);
		Assert.assertEquals(2.0, props[1].getPrice());
		
		engine.processSteps(1, mrrs);
		props = mrrs.getSellPropositionsList(wood);
		p = props[0];
		if (p.getSellerMoneyAccount().getBalance() < 1e7) {
			p = props[1];
		}
		ResourceUtils.sortSellPropositions(props);
		Assert.assertEquals(2, props.length);
		Assert.assertEquals(3.0, p.getPrice());
		
		engine.processSteps(1, mrrs);
		props = mrrs.getSellPropositionsList(wood);
		p = props[0];
		if (p.getSellerMoneyAccount().getBalance() < 1e7) {
			p = props[1];
		}
		ResourceUtils.sortSellPropositions(props);
		Assert.assertEquals(2, props.length);
		Assert.assertEquals(6.0, p.getPrice());
	}

	public void testSpeculantPropositionsCountPart() {
		IResourceType wood = new ResourceType("Wood");
		IMarketResourceRedestributionSystem mrrs =
				new DefaultMarketResourceRedestributionSystem();
		ResellResourceExpensiveSpeculantAgent speculant =
				new ResellResourceExpensiveSpeculantAgent(
						wood,
						mrrs,
						0.7,
						0.7
				);
		for (int i = 0; i < 100; i++) {
			ResourceStorrage storr = new ResourceStorrage();
			storr.storeResource(wood, 1.0);
			mrrs.registerProposition(new SellProposition(wood, 1.0, storr, new MoneyAccount()));
		}
		speculant.processPreProduceStage();
		speculant.processProduceStage();
		speculant.processPostProduceStage();
		int counter = 0;
		for (ISellProposition sp : mrrs.getSellPropositionsCollection()) {
			if (sp.getPrice() > 1.5) {
				counter++;
			}
		}
		Assert.assertEquals(70, counter);
	}

	public void testSpeculantPurchaseValueLimit() {
		IResourceType wood = new ResourceType("Wood");
		IMarketResourceRedestributionSystem mrrs =
				new DefaultMarketResourceRedestributionSystem();
		ResellResourceExpensiveSpeculantAgent speculant =
				new ResellResourceExpensiveSpeculantAgent(
						wood,
						mrrs,
						0.7,
						0.456
				);
		for (int i = 0; i < 100; i++) {
			ResourceStorrage storr = new ResourceStorrage();
			storr.storeResource(wood, 1.0);
			mrrs.registerProposition(new SellProposition(wood, 1.0, storr, new MoneyAccount()));
		}
		speculant.processPreProduceStage();
		speculant.processProduceStage();
		speculant.processPostProduceStage();
		double purchasedValue = -1.0;
		for (ISellProposition sp : mrrs.getSellPropositionsCollection()) {
			if (sp.getPrice() > 1.5) {
				purchasedValue = sp.getSellerStorrage().howMuchWasStored(wood);
			}
		}
		Assert.assertEquals(45.6, purchasedValue);
	}

	public void test_AntBasedAgentsCreator_vs_Graig() {
		JEBExperimentFlow experimentFlow = new JEBExperimentFlow();
		
		GraigExperimentSettings settings = 
			new GraigExperimentSettings();
		
		settings.initialise();
		
		settings.stepSize = 100;
		settings.stepCount = 190;
		settings.agentsCount = 50;
		settings.initMoney = 50.0;
		settings.initResourceExceedPercent = 1.2;
		settings.antAgentCount = 7;
		
		settings.chainLength = 5;
		settings.branchesCount = 5;
		settings.postBranchCount = 0;

		settings.agentGreedPercent = 1.5;
		settings.produceProfit = 1.15;
		settings.concurrentPricePercent = 0.5;
		settings.observeCostsTraceLength = 15;
		
		settings.rrsFactory = new DefaultMarketRRSFactory();
		settings.resources = ResourceUtils.generateResources("r", 9);
		settings.experiment = experimentFlow; 
		settings.randomSeed = 0.0; 
		settings.zeroPoint = new Point(0.0, 0.0);
		
		settings.purchaseExceedDayBudget = settings.initMoney * settings.agentsCount / settings.stepSize;
		settings.purchaseExceedPassivePeriod = settings.stepSize;
		settings.purchaseExceedUseTrackLength = (int) (settings.stepSize * 1.5);
		settings.utiliseExceedPeriod = settings.stepSize;
		settings.selectPropositionsPart = 0.8;
		settings.feramonHistoryLength = 5;
		settings.setCommoditiesComplementaryGroupsPower(7.0);
		settings.setCommoditiesComplementaryGroups(new int[][] {
				new int[] { 0, 1, 2, 3 },
				new int[] { 4, 5, 6, 7, 8 }
		}); 
		settings.profitCostManagerFactory = GoalGroupComplementaryBasedProfitCostGen.FACTORY_INSTANCE;
		settings.goalResourceIndex = 0;
		settings.timeStepX = 100;
		settings.speculantPropCountMarketPart = 0.5;
		settings.speculantGoalValueMarketPart = 0.1;
		
		settings.validate();
		
		AntBasedAgentsCreator antAgentsCreator = new AntBasedAgentsCreator();
		INode[] automatas = new INode[] { new Node("root") };
		IExperimentContext experimentContext = settings.getExperimentContextFactory().newContext(settings);
		IEconomicProducer[] agents = antAgentsCreator.automata2agents(automatas, experimentContext);
		Assert.assertEquals(1, agents.length);
		
		BrosnenEngineInitialiser brosnenEngineInitialiser = new BrosnenEngineInitialiser();
		IEconomicEngine engine = new EconomicEngine();
		brosnenEngineInitialiser.initialise(engine, agents, experimentContext);
	}
}
